package br.org.acessobrasil.processoacessibilidade.dao.util;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.Query;

import org.apache.log4j.Logger;
public class EntityManagerAutoCommit implements EntityManager{
	private static Logger logger= Logger.getLogger(EntityManagerAutoCommit.class);
	private EntityManager em;
	private EntityManagerFactory entityManagerFactory;
	public EntityManagerAutoCommit(EntityManager em, EntityManagerFactory entityManagerFactory){
		this.em = em;
		this.entityManagerFactory = entityManagerFactory;
	}
	@Override
	public void clear() {
		this.em.clear();
	}

	@Override
	public void close() {
		this.em.close();		
	}

	@Override
	public boolean contains(Object entity) {
		return this.em.contains(entity);
	}

	@Override
	public Query createNamedQuery(String name) {
		EntityManager em = entityManagerFactory.createEntityManager();
		return em.createNamedQuery(name);
	}

	@Override
	public Query createNativeQuery(String sqlString) {
		EntityManager em = entityManagerFactory.createEntityManager();
		return em.createNativeQuery(sqlString);
	}

	@Override
	public Query createNativeQuery(String sqlString, Class resultClass) {
		EntityManager em = entityManagerFactory.createEntityManager();
		return em.createNativeQuery(sqlString, resultClass);
	}

	@Override
	public Query createNativeQuery(String sqlString, String resultSetMapping) {
		EntityManager em = entityManagerFactory.createEntityManager();
		return em.createNativeQuery(sqlString, resultSetMapping);
	}

	@Override
	public Query createQuery(String qlString) {
		EntityManager em = entityManagerFactory.createEntityManager();
		return em.createQuery(qlString);
	}

	@Override
	public <T> T find(Class<T> entityClass, Object primaryKey) {
		return findSinc(entityClass, primaryKey);
	}

	public synchronized <T> T findSinc(Class<T> entityClass, Object primaryKey) {
		synchronized (em) {
			try{
				em.getTransaction().begin();
				T t = em.find(entityClass, primaryKey);
				em.getTransaction().commit();
				return t;
			}catch(Exception e){
				logger.error("",e);
				em.getTransaction().rollback();
				throw new RuntimeException();
			}
		}
	}
	
	@Override
	public void flush() {
		em.flush();
	}

	@Override
	public Object getDelegate() {
		return em.getDelegate();
	}

	@Override
	public FlushModeType getFlushMode() {
		return em.getFlushMode();
	}

	@Override
	public <T> T getReference(Class<T> entityClass, Object primaryKey) {
		return em.getReference(entityClass, primaryKey);
	}

	@Override
	public EntityTransaction getTransaction() {
		return em.getTransaction();
	}

	@Override
	public boolean isOpen() {
		return em.isOpen();
	}

	@Override
	public void joinTransaction() {
		em.joinTransaction();
	}

	@Override
	public void lock(Object entity, LockModeType lockMode) {
		em.lock(entity, lockMode);
	}

	@Override
	public <T> T merge(T entity) {
		return mergeSync(entity);
	}
	private synchronized  <T> T mergeSync(T entity) {
		synchronized (em) {
			try{
				em.getTransaction().begin();
				T t = em.merge(entity);
				em.getTransaction().commit();
				return t;
			}catch(Exception e){
				logger.error("",e);
				em.getTransaction().rollback();
				throw new RuntimeException();
			}
		}
	}

	@Override
	public void persist(Object entity) {
		persistSinc(entity);
	}
	private synchronized void persistSinc(Object entity){
		synchronized (em) {
			try{
				em.getTransaction().begin();
				em.persist(entity);
				em.flush();
				em.getTransaction().commit();
			}catch(Exception e){
				logger.error("",e);
				em.getTransaction().rollback();
				throw new RuntimeException();
			}
		}
	}

	@Override
	public void refresh(Object entity) {
		em.refresh(entity);
	}

	@Override
	public void remove(Object entity) {
		synchronized (em) {
			try{
				em.getTransaction().begin();
				em.remove(entity);
				em.flush();
				em.getTransaction().commit();
			}catch(Exception e){
				logger.error("",e);
				em.getTransaction().rollback();
				throw new RuntimeException();
			}
		}
	}

	@Override
	public void setFlushMode(FlushModeType flushMode) {
		em.setFlushMode(flushMode);
	}

}
